package com.sys.basics.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.commons.lang3.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sys.basics.config.constant.AttachmentConstant;
import com.sys.basics.config.constant.SystemConstant;
import com.sys.basics.entity.SysUser;
import com.sys.basics.utils.ShiroUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import com.sys.basics.entity.SysAttachment;
import com.sys.basics.dao.SysAttachmentDao;
import com.sys.basics.service.SysAttachmentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;


/**
 * @author: ares
 * @date: 2021-10-08
 * @description: 附件资源表 服务实现类
 */
@Slf4j
@Transactional(rollbackFor = Exception.class)
@Service
public class SysAttachmentServiceImpl extends ServiceImpl<SysAttachmentDao, SysAttachment> implements SysAttachmentService {
    @Autowired
    SysAttachmentDao sysAttachmentDao;

    private String ROOT_PATH = SystemConstant.ATTACHMENT_ROOT;

    @Override
    public String uploadSingle(Long parentId, MultipartFile file) throws IOException {
        return saveAttachment(parentId, file);
    }

    @Override
    public List<String> uploadMultipart(Long parentId, MultipartFile[] files) throws IOException {
        ArrayList<String> urlList = new ArrayList<>();
        if (files.length > 0) {
            for (MultipartFile file : files) {
                String url = saveAttachment(parentId, file);
                if (StringUtils.isNotEmpty(url)) {
                    urlList.add(url);
                }
            }
        }
        return urlList;
    }

    @Override
    public IPage<SysAttachment> getPages(Page<SysAttachment> page, SysAttachment attachment) {
        return sysAttachmentDao.getPages(page, attachment);
    }

    @Override
    public SysAttachment getTreeById(Long id) {
        return sysAttachmentDao.getTreeById(id);
    }

    @Override
    public List<SysAttachment> getChildrenByParentId(Long parentId) {
        return sysAttachmentDao.getChildrenByParentId(parentId);
    }

    @Override
    public List<SysAttachment> getChildrenTreeByParentId(Long parentId) {
        return sysAttachmentDao.getChildrenTreeByParentId(parentId);
    }

    @Override
    public List<SysAttachment> getDirectoryTreeByParentId(Long parentId) {
        return sysAttachmentDao.getDirectoryTreeByParentId(parentId);
    }

    @Override
    public SysAttachment getTreeByIdAsLeaf(Long id) {
        return getParent(sysAttachmentDao.selectById(id));
    }

    @Override
    public boolean removeSelfAndChildrenById(Long id) {
        List<SysAttachment> children = sysAttachmentDao.getChildrenByParentId(id);
        if (children.size() > 0) {
            children.forEach(child -> removeSelfAndChildrenById(child.getId()));
        }
        return super.removeById(id);
    }

    @Override
    public boolean createDirectory(Long parentId, String name) {
        SysUser userInfo = ShiroUtils.getUserInfo();
        SysAttachment sysAttachment = new SysAttachment();

        sysAttachment.setOrgId(userInfo.getDefaultOrgId());
        sysAttachment.setParentId(parentId);
        sysAttachment.setName(name);
        sysAttachment.setProtocol(SystemConstant.ATTACHMENT_PROTOCOL);
        sysAttachment.setType(AttachmentConstant.DIRECTORY);

        int insertNum = sysAttachmentDao.insert(sysAttachment);
        return insertNum > 0;
    }

    @Override
    public boolean reNameDirectory(Long id, String name) {
        SysAttachment sysAttachment = new SysAttachment();
        sysAttachment.setId(id);
        sysAttachment.setName(name);
        int updatedNum = sysAttachmentDao.updateById(sysAttachment);
        return updatedNum > 0;
    }

    @Override
    public boolean batchMove(Long id, List<Long> attachmentIds) {
        return sysAttachmentDao.batchMove(id, attachmentIds);
    }

    @Override
    public boolean batchRemove(List<Long> attachmentIds) {
        for (Long attachmentId : attachmentIds) {
            SysAttachment attachment = sysAttachmentDao.selectById(attachmentId);
            if (ObjectUtil.isNotNull(attachment)) {
                if (attachment.getType().equals(AttachmentConstant.DIRECTORY)) {
                    removeDirectoryAndChildren(attachment);
                    sysAttachmentDao.deleteById(attachmentId);
                } else {
                    removeNotDirectoryAttachment(attachment);
                }
            }
        }
        return true;
    }

    @Override
    public SysAttachment getDirectoryByName(Long parentId, String name) {
        return sysAttachmentDao.getDirectoryByName(parentId, name);
    }

    /**
     * @param children
     * @return
     * @author: ares
     * @date: 2021/9/30 22:10
     * @description: 根据子节点查询父节点
     */
    private SysAttachment getParent(SysAttachment children) {
        if (children == null) return null;
        Long parentId = children.getParentId();
        if (parentId == 0) {
            return children;
        } else {
            SysAttachment parent = sysAttachmentDao.selectById(parentId);
            parent.setChildren(Arrays.asList(children));
            return getParent(parent);
        }
    }

    /**
     * @param parentId
     * @param file
     * @return
     * @throws IOException
     * @author: ares
     * @date: 2021/10/25 14:51
     * @description: 保存附件
     */
    private String saveAttachment(Long parentId, MultipartFile file) throws IOException {
        SysUser userInfo = ShiroUtils.getUserInfo();
        String savePath = ROOT_PATH;

        SysAttachment sysAttachment = new SysAttachment();

        String filename = new Date().getTime() + "_" + file.getOriginalFilename();
        String mime = file.getContentType();
        String[] mimeSplit = mime.split("/");
        String ext = mimeSplit[1];
        long size = file.getSize();
        HashMap<String, Integer> pixel = new HashMap<>();

        String url = savePath + filename;
        Integer type = AttachmentConstant.ATTACHMENT;

        switch (mimeSplit[0]) {
            case "image":
                type = AttachmentConstant.IMAGE;
                break;
            case "video":
                type = AttachmentConstant.VIDEO;
                break;
        }

        if (type.equals(AttachmentConstant.IMAGE)) {
            InputStream tempImageInputStream = new ByteArrayInputStream(file.getBytes());
            BufferedImage buff = ImageIO.read(tempImageInputStream);
            Integer width = buff.getWidth();   //得到图片的宽度
            Integer height = buff.getHeight();  //得到图片的高度
            tempImageInputStream.close(); //关闭Stream
            pixel.put("width", width);
            pixel.put("height", height);
            sysAttachment.setPixel(JSONUtil.toJsonStr(pixel));
        }

        File saveFile = new File(SystemConstant.ATTACHMENT_DRIVE + url);

        sysAttachment.setOrgId(userInfo.getDefaultOrgId());
        sysAttachment.setParentId(parentId);
        sysAttachment.setName(filename);
        sysAttachment.setMime(mime);
        sysAttachment.setExt(ext);
        sysAttachment.setSize((int) size);
        sysAttachment.setUrl(url);
        sysAttachment.setProtocol(SystemConstant.ATTACHMENT_PROTOCOL);
        sysAttachment.setType(type);

        int insertNum = sysAttachmentDao.insert(sysAttachment);
        if (insertNum > 0) {
            file.transferTo(saveFile);
            return url;
        }
        return "";
    }

    /**
     * @author: ares
     * @date: 2021/10/27 13:57
     * @description: 删除目录
     * @param attachment
     */
    private void removeDirectoryAndChildren(SysAttachment attachment) {
        List<SysAttachment> children = getChildrenByParentId(attachment.getId());
        if (ArrayUtil.isEmpty(children)) {
            sysAttachmentDao.deleteById(attachment.getId());
        } else {
            for (SysAttachment att : children) {
                if (att.getType().equals(AttachmentConstant.DIRECTORY)) {
                    removeDirectoryAndChildren(att);
                    sysAttachmentDao.deleteById(att.getId());
                } else {
                    removeNotDirectoryAttachment(att);
                }
            }
        }
    }

    /**
     * @param attachment
     * @author: ares
     * @date: 2021/10/27 13:51
     * @description: 删除非目录附件资源
     */
    private void removeNotDirectoryAttachment(SysAttachment attachment) {
        int deletedNum = sysAttachmentDao.deleteById(attachment.getId());
        if (deletedNum == 1) {
            FileUtil.del(SystemConstant.ATTACHMENT_DRIVE + attachment.getUrl());
        }
    }
}
